﻿using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace FsAddInManager.Utils.InitFile
{
 /// <summary>
    /// ini文件操作类
    /// </summary>
    public class InitFile
    {
        /// <summary>
        /// The m_file name
        /// </summary>
        private readonly string m_fileName = "";

        /// <summary>
        /// 初始化ini文件
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public InitFile(string fileName)
        {
            Debug.Assert(fileName.Length > 0);

            m_fileName = fileName;
            EnsureFileExist();
        }

        /// <summary>
        /// 初始化ini文件
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="curField">当前分组</param>
        public InitFile(string fileName, string curField)
        {
            Debug.Assert(fileName.Length > 0);

            m_fileName = fileName;
            CurField = curField;
            EnsureFileExist();
        }

        /// <summary>
        /// 当前操作的域
        /// </summary>
        /// <value>The current field.</value>
        public string CurField { get; set; }

        /// <summary>
        /// 写入字符串
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="value">值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string field, string key, string value)
        {
            return Kernel32.WritePrivateProfileString(field, key, value, m_fileName);
        }

        /// <summary>
        /// 写入整形值
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="nValue">值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string field, string key, int nValue)
        {
            return SetValueOfKey(field, key, string.Format("{0}", nValue));
        }

        /// <summary>
        /// 写入字节值
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="byteValue">字节值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string field, string key, byte byteValue)
        {
            return SetValueOfKey(field, key, string.Format("{0}", byteValue));
        }

        /// <summary>
        /// 写入布尔值
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="bValue">布尔值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string field, string key, bool bValue)
        {
            return SetValueOfKey(field, key, string.Format("{0}", bValue));
        }

        /// <summary>
        /// 写入双精值
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="dValue">The d value.</param>
        /// <param name="decimalPlaces">保留小数位数</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string field, string key, double dValue, int decimalPlaces = 2)
        {
            return SetValueOfKey(field, key, string.Format("{0}", dValue.ToString("F" + decimalPlaces)));
        }

        /// <summary>
        /// 读取字符串
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="value">读取的字符串</param>
        /// <returns>是否成功读取</returns>
        public bool GetValueOfKey(string field, string key, ref string value)
        {
            var size = 2560;
            var sb = new StringBuilder(size);
            var count = Kernel32.GetPrivateProfileString(field, key, "", sb, size, m_fileName);
            if (count > 0)
                value = sb.ToString();
            return count > 0;
        }

        /// <summary>
        /// 读取整型
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="nValue">整型值</param>
        /// <returns>是否成功读取</returns>
        public bool GetValueOfKey(string field, string key, ref int nValue)
        {
            var strVal = string.Empty;
            if (GetValueOfKey(field, key, ref strVal))
            {
                // 如果存成了double型的字符串，直接转换会异常
                if (!int.TryParse(strVal, out nValue))
                {
                    double d = 0;
                    if (!double.TryParse(strVal, out d))
                    {
                        throw new FormatException(string.Format("未处理的格式, 内容：{0}", strVal));
                    }

                    nValue = Convert.ToInt32(d);
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// 读取字节型
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="bValue">字节值</param>
        /// <returns>是否成功读取</returns>
        public bool GetValueOfKey(string field, string key, ref byte bValue)
        {
            var strVal = string.Empty;
            if (GetValueOfKey(field, key, ref strVal))
            {
                bValue = Convert.ToByte(strVal);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 读取布尔型
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="bValue">布尔值</param>
        /// <returns>是否成功读取</returns>
        public bool GetValueOfKey(string field, string key, ref bool bValue)
        {
            var strVal = string.Empty;
            if (GetValueOfKey(field, key, ref strVal))
            {
                bValue = Convert.ToBoolean(strVal);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 读取双精型
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <param name="dValue">双精值</param>
        /// <returns>是否成功读取</returns>
        public bool GetValueOfKey(string field, string key, ref double dValue)
        {
            var strVal = string.Empty;
            if (GetValueOfKey(field, key, ref strVal))
            {
                dValue = Convert.ToDouble(strVal);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 字符串型读取
        /// </summary>
        /// <param name="field">域</param>
        /// <param name="key">键名</param>
        /// <returns>字符串值</returns>
        public string GetValueOfKey(string field, string key)
        {
            var value = "";
            GetValueOfKey(field, key, ref value);
            return value;
        }

        /// <summary>
        /// 字符串型读取
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool GetValueOfKey(string key, ref string value)
        {
            return GetValueOfKey(CurField, key, ref value);
        }

        /// <summary>
        /// 读取整型
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool GetValueOfKey(string key, ref int value)
        {
            return GetValueOfKey(CurField, key, ref value);
        }

        /// <summary>
        /// 读取布尔型
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool GetValueOfKey(string key, ref bool value)
        {
            return GetValueOfKey(CurField, key, ref value);
        }

        /// <summary>
        /// 读取双精型
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool GetValueOfKey(string key, ref double value)
        {
            return GetValueOfKey(CurField, key, ref value);
        }

        /// <summary>
        /// 读取字节型
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool GetValueOfKey(string key, ref byte value)
        {
            return GetValueOfKey(CurField, key, ref value);
        }

        /*
        /// <summary>
        /// 获取某域的所有键值对（测试为只能出一行）
        /// </summary>
        /// <param name="field"></param>
        /// <param name="buffer"></param>
        /// <param name="items"></param>
        /// <returns></returns>
         public bool GetSectionValues(string field, int buffer, ref List<IniFileItem> items)
         {
             items.Clear();
             Debug.Assert(File.Exists(m_fileName));

             sbyte[] lpReturnedString = new sbyte[buffer];
             uint len = Kernel32.GetPrivateProfileSection(field,
                lpReturnedString, (uint)lpReturnedString.Length, m_fileName);
            
             items.Clear();
             if (len > 0)
             {
                 unsafe
                 {
                     fixed (sbyte* pBuf = lpReturnedString)
                     {
                         // 动态解析出所有的Item
                         int pos1 = 0, pos2 = 0; // pos1指向Item的第一个字符，pos2指向Item后面的NULL字符
                         while (pos2 < len)
                         {
                             if (pBuf[pos2] != '\0')
                             {
                                 pos2++;
                             }
                             else
                             {
                                 // pos2已经到达当前Item的结尾
                                 //CString item = pszItem;
                                 string item = new string(pBuf,
                                 pos1, pos2 - pos1, Encoding.Default);
                                 int pos = item.IndexOf("=");
                                 if (pos > 0)
                                 {
                                     IniFileItem ifi = new IniFileItem();
                                     ifi.key = item.Substring(0, pos);
                                     ifi.value = item.Substring(pos + 1);
                                     if (ifi.key.Length > 0 && ifi.value.Length > 0)
                                     {
                                         items.Add(ifi);
                                     }
                                 }

                                 pos2++;
                                 pos1 = pos2;
                             }
                         }
                     }
                 }
             } 
             return len > 0;
         }
         */

        /// 确保INI文件存在
        /// <summary>
        /// Ensures the file exist.
        /// </summary>
        private void EnsureFileExist()
        {
            var pos = m_fileName.LastIndexOf("\\");
            if (pos >= 0)
            {
                var directory = m_fileName.Substring(0, pos);
                if (!Directory.Exists(directory))
                    Directory.CreateDirectory(directory);

                if (!File.Exists(m_fileName))
                {
                    var sw = new StreamWriter(m_fileName);
                    sw.Close();
                }
            }
        }

        /// <summary>
        /// 字符串型读取（确保CurField不为空）
        /// </summary>
        /// <param name="key">键名</param>
        /// <returns>字符串值</returns>
        public string GetValueOfKey(string key)
        {
            var value = "";
            GetValueOfKey(CurField, key, ref value);
            return value;
        }

        /// <summary>
        /// 布尔型读取（确保CurField不为空）
        /// </summary>
        /// <param name="key">键名</param>
        /// <returns>字符串值</returns>
        public bool GetValueOfKeyB(string key)
        {
            var value = false;
            GetValueOfKey(CurField, key, ref value);
            return value;
        }

        /// <summary>
        /// Int型读取（确保CurField不为空）
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>System.Int32.</returns>
        public int GetValueOfKeyI(string key)
        {
            var value = 0;
            GetValueOfKey(CurField, key, ref value);
            return value;
        }

        /// <summary>
        /// double型读取（确保CurField不为空）
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>System.Double.</returns>
        public double GetValueOfKeyD(string key)
        {
            double value = 0;
            GetValueOfKey(CurField, key, ref value);
            return value;
        }

        /// <summary>
        /// 写入字符串（确保CurField不为空）
        /// </summary>
        /// <param name="key">键名</param>
        /// <param name="value">值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string key, string value)
        {
            return SetValueOfKey(CurField, key, value);
        }

        /// <summary>
        /// 写入字符串（确保CurField不为空）
        /// </summary>
        /// <param name="key">键名</param>
        /// <param name="value">值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string key, bool value)
        {
            return SetValueOfKey(CurField, key, value);
        }

        /// <summary>
        /// 写入字符串（确保CurField不为空）
        /// </summary>
        /// <param name="key">键名</param>
        /// <param name="value">值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string key, int value)
        {
            return SetValueOfKey(CurField, key, value);
        }

        /// <summary>
        /// 写入字符串（确保CurField不为空）
        /// </summary>
        /// <param name="key">键名</param>
        /// <param name="value">值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string key, double value)
        {
            return SetValueOfKey(CurField, key, value);
        }

        /// <summary>
        /// 写入字符串（确保CurField不为空）
        /// </summary>
        /// <param name="key">键名</param>
        /// <param name="value">值</param>
        /// <returns>是否成功写入</returns>
        public bool SetValueOfKey(string key, byte value)
        {
            return SetValueOfKey(CurField, key, value);
        }

        /// <summary>
        /// 删除ini文件下所有段落
        /// </summary>
        public void ClearAllSection()
        {
            SetValueOfKey(null, null, null);
        }

        /// <summary>
        /// 删除ini文件下指定段落下的所有键
        /// </summary>
        /// <param name="Section"></param>
        public void ClearSection(string Section)
        {
            SetValueOfKey(Section, null, null);
        }
    }

    /// <summary>
    /// Class IniFileItem.
    /// </summary>
    public class IniFileItem
    {
        public string key { get; set; }
        public string value { get; set; }
    }
}
